/***************************************************************************
	debugstreams.h  - sets up debugging sinks
			
	Basically, dout(LEVEL) returns clog if the debug level is higher
	than LEVEL or a dummy ostream if lower
	The level can be set by dout.setLevel(LEVEL)

Usage:

Really Simple!

By including debugstream.h, you have access to the "dout" 
instance of the Debug class.
 
You use it just like cout, with a modifier for level

   dout.setLevel(ALL);  // print all levels of output

   dout(INFO) << "This is some information I wish to log\n";
	

   dout.setLevel(RELEASE);
	
   dout(ERR) << This error will be printed since it is important\n";
   dout(INFO) << "This info was meant just for the developer and "
              << "will not be printed at this debug level" << endl;
	           
***************************************************************************/

#ifndef DEBUGSTREAMS_H
#define DEBUGSTREAMS_H

#include "CColor.h"
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

#ifdef NDEBUG
// define this dummy macro
#define dout(X) 1 ? (void)0 : (void) cerr
#else


// create dummy stream which just dumps all output
// this is what we use if the DebugLevel is higher than the message importance
// this stream sets a failbit and hence won't attempt to process it's input
static ostream nullstream(NULL);

class teebuf: public std::streambuf 
{
 public:
  teebuf(std::streambuf* sbuf1, std::streambuf* sbuf2):
    m_sbuf1(sbuf1), m_sbuf2(sbuf2) {}
 private:
  int_type overflow(int_type c) 
    {
      if (m_sbuf1->sputc(c) == traits_type::eof())
	return traits_type::eof();
      if (m_sbuf2->sputc(c) == traits_type::eof())
	return traits_type::eof();
      return traits_type::not_eof(c);
    }
  std::streambuf* m_sbuf1;
  std::streambuf* m_sbuf2;
};



/* describing the debug levels
   ALL      show all messages
   MEM      ultra-detailed memory leak debugging
   DEBUG    timing profile messages
   LFUNC    function announcements that might be in loops
   LINFO    msgs that may be in loops
   FUNC     function announcement
   INFO     general info
   BLANK    same level as INFO - does not write "    INFO:" prior to message
   PROGRESS 
   RELEASE  stuff that you'd want to stick in a log file even after release
   WARN     somethings wrong, e.g. input.  Beeps too!
   ERR      DISASTER                       Beeps too!
*/

enum DebugLevelType { ALL, MEM, DEBUG, LFUNC, LINFO, FUNC, INFO, BLANK, 
			PROGRESS, RELEASE, WARN, ERR, OFF };

//static DebugLevelType itsLevel = INFO;

class Debug
{
 public:
  
  Debug ();
  ~Debug();
  ostream& operator()(const DebugLevelType& Level);
  static void setLevel(const DebugLevelType& Level);
  static string printLevel();
  DebugLevelType getLevel() const;
  static CColor Default;
  // static void LogToFile(const char* LogFileName, const DebugLevelType& Level);
 private:
  static DebugLevelType itsLevel;
  static CColor Tab[12];
};

static Debug dout;

inline ostream& endreq(ostream& os)
{
  os << Debug::Default.getColorCode() << endl << flush;
  return os;
}

#endif // NDEBUG

#endif // DEBUGSTREAMS_H
